
<!DOCTYPE html>
<html>
  <head>
    
<meta charset="utf-8" >

<title>神经网络的压缩优化方法总结 | dragon</title>
<meta name="description" content="邮箱(base64)：MTY5MDMwMjk2M0BxcS5jb20=
">

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.7.0/animate.min.css">

<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
<link rel="shortcut icon" href="https://dragonfive.gitee.io//favicon.ico?v=1740893463017">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.10.0/katex.min.css">
<link rel="stylesheet" href="https://dragonfive.gitee.io//styles/main.css">



<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="//cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.5.1/build/highlight.min.js"></script>



  </head>
  <body>
    <div id="app" class="main">
      <div class="site-header-container">
  <div class="site-header">
    <div class="left">
      <a href="https://dragonfive.gitee.io/">
        <img class="avatar" src="https://dragonfive.gitee.io//images/avatar.png?v=1740893463017" alt="" width="32px" height="32px">
      </a>
      <a href="https://dragonfive.gitee.io/">
        <h1 class="site-title">dragon</h1>
      </a>
    </div>
    <div class="right">
      <transition name="fade">
        <i class="icon" :class="{ 'icon-close-outline': menuVisible, 'icon-menu-outline': !menuVisible }" @click="menuVisible = !menuVisible"></i>
      </transition>
    </div>
  </div>
</div>

<transition name="fade">
  <div class="menu-container" style="display: none;" v-show="menuVisible">
    <div class="menu-list">
      
        
          <a href="/" class="menu purple-link">
            首页
          </a>
        
      
        
          <a href="/archives" class="menu purple-link">
            归档
          </a>
        
      
        
          <a href="/tags" class="menu purple-link">
            标签
          </a>
        
      
        
          <a href="/post/about" class="menu purple-link">
            关于
          </a>
        
      
    </div>
  </div>
</transition>


      <div class="content-container">
        <div class="post-detail">
          
          <h2 class="post-title">神经网络的压缩优化方法总结</h2>
          <div class="post-info post-detail-info">
            <span><i class="icon-calendar-outline"></i> 2017-08-05</span>
            
              <span>
                <i class="icon-pricetags-outline"></i>
                
                  <a href="https://dragonfive.gitee.io/tag/MLJqs9GOQ/">
                    networker
                    
                      ，
                    
                  </a>
                
                  <a href="https://dragonfive.gitee.io/tag/LI4Uk3FeTa/">
                    网络压缩
                    
                      ，
                    
                  </a>
                
                  <a href="https://dragonfive.gitee.io/tag/o9zBQ9B4NY/">
                    神经网络
                    
                      ，
                    
                  </a>
                
                  <a href="https://dragonfive.gitee.io/tag/WzibKNMac/">
                    深度学习
                    
                  </a>
                
              </span>
            
          </div>
          <div class="post-content" v-pre>
            <hr>
<p>title: 神经网络的压缩优化方法总结</p>
<p>date: 2017/8/5 12:04:12</p>
<p>categories:</p>
<ul>
<li>深度学习<br>
tags:</li>
<li>deeplearning</li>
<li>网络优化</li>
<li>神经网络</li>
</ul>
<hr>
<p>这里回顾一下几个经典模型，我们主要看看深度和caffe模型大小，<a href="https://dragonfive.github.io/2017-07-05/deep_learning_model/">神经网络模型演化</a>。并总结一些模型压缩优化的方法。</p>
<figure data-type="image" tabindex="1"><img src="https://www.github.com/DragonFive/CVBasicOp/raw/master/1502693251377.jpg" alt="各种CNN模型" loading="lazy"></figure>
<p>模型大小(参数量)和模型的深浅并非是正相关。</p>
<h1 id="一些经典的模型-修改网络架构">一些经典的模型-修改网络架构</h1>
<h2 id="fully-connect-to-local-connect-全连接到卷积神经网络-1x1卷积">fully connect to local connect 全连接到卷积神经网络  1x1卷积</h2>
<p>Alexnet<a href="https://www.github.com/DragonFive/CVBasicOp/raw/master/1502693251377.jpg">1</a>是一个8层的卷积神经网络，有约<strong>60M个参数</strong>，如果采用<strong>32bit float存下来有200M</strong>。值得一提的是，AlexNet中仍然有3个全连接层，其参数量占比参数总量超过了90%。</p>
<p>下面举一个例子，假如输入为28×28×192，输出feature map通道数为128。那么，直接接3×3卷积，参数量为3×3×192×128=221184。</p>
<p>如果先用<strong>1×1卷积进行降维到96个通道</strong>，然后再用3×3升维到128，则参数量为：1×1×192×96+3×3×96×128=129024，参数量减少一半。虽然参数量减少不是很明显，但是如果1×1输出维度降低到48呢？则参数量又减少一半。对于上千层的大网络来说，效果还是很明显了。</p>
<p>移动端对模型大小很敏感。下载一个100M的app与50M的app，首先用户心理接受程度就不一样。</p>
<p>原则上降低通道数是会降低性能的，这里为什么却可以降维呢？我们可以从很多embedding技术，比如PCA等中得到思考，<strong>降低一定的维度可以去除冗余数据</strong>，损失的精度其实很多情况下都不会对我们解决问题有很大影响。</p>
<p>1×1卷积，在 GoogLeNet Inception v1以及后续版本，ResNet中都大量得到应用，<strong>有减少模型参数</strong>的作用。</p>
<h2 id="卷积拆分">卷积拆分</h2>
<p>(1) VGG</p>
<p>VGG可以认为是AlexNet的增强版，<strong>两倍的深度，两倍的参数量</strong>。不过，也提出了一个模型压缩的trick，后来也被广泛借鉴。</p>
<p>那就是，<strong>对于5×5的卷积，使用两个3×3的卷积串联</strong>，可以得到同样的感受野，但参数量却有所降低，为3×3×2/(5×5)=0.72，同样的道理3个3×3卷积代替一个7×7，则参数压缩比3×3×3/(7×7)=0.55，降低一倍的参数量，也是很可观的。</p>
<p>(2) GoogLeNet</p>
<p>GoogleLet Inception v2就借鉴了VGG上面的思想。而到了Inception V3网络，则更进一步，将大卷积分解(Factorization)为小卷积。</p>
<p>比如<strong>7×7的卷积，拆分成1×7和7×1</strong>的卷积后。参数量压缩比为1×7×2/(7×7)=0.29，比上面拆分成3个3×3的卷积，更加节省参数了。</p>
<p>问题是这种<strong>非对称的拆分</strong>，居然比对称地拆分成几个小卷积核改进效果更明显，<strong>增加了特征多样性</strong>。</p>
<p>后来的Resnet就不说了，也是上面这些trick。到现在，基本上网络中都是3×3卷积和1×1卷积，5×5很少见，7×7几乎不可见。</p>
<p>(3) SqueezeNet</p>
<p>squeezenet将上面1×1降维的思想进一步拓展。通过减少3×3的filter数量，将其一部分替换为1×1来实现压缩。</p>
<p>具体的一个子结构如下：一个squeeze模块加上一个expand模块，使squeeze中的通道数量，少于expand通道数量就行。</p>
<figure data-type="image" tabindex="2"><img src="https://www.github.com/DragonFive/CVBasicOp/raw/master/1502694686047.jpg" alt="squeezenet网络的expand模块" loading="lazy"></figure>
<p>假如输入为M维，如果直接接3×3卷积，输出为7个通道，则参数量：M×3×3×7。</p>
<p>如果按上图的做法，则参数量为M×1×1×3+3×4×1×1+3×4×3×3，压缩比为：(40+M)/21M，当M比较大时，约0.05。</p>
<p>文章最终<strong>将AlexNet压缩到原来1/50</strong>，而性能几乎不变。</p>
<hr>
<p>SqueezeNet的核心指导思想是——在保证精度的同时使用最少的参数。而这也是所有模型压缩方法的一个终极目标。</p>
<p>基于这个思想，SqueezeNet提出了3点网络结构设计策略：</p>
<p>策略 1. 将3x3卷积核替换为1x1卷积核。</p>
<p>这一策略很好理解，因为1个1x1卷积核的参数是3x3卷积核参数的1/9，这一改动理论上可以将模型尺寸压缩9倍。</p>
<p>策略 2. 减小输入到3x3卷积核的输入通道数。</p>
<p>我们知道，对于一个采用3x3卷积核的卷积层，该层所有卷积参数的数量（不考虑偏置）为：<br>
<img src="https://www.github.com/DragonFive/CVBasicOp/raw/master/1507038803077.jpg" alt="enter description here" loading="lazy"></p>
<p>N是卷积核的数量，也即输出通道数，C是输入通道数。因此，为了保证减小网络参数，<strong>不仅仅需要减少3x3卷积核的数量，还需减少输入到3x3卷积核的输入通道数量</strong>，即式中C的数量。</p>
<p>策略 3.尽可能的将降采样放在网络后面的层中。</p>
<p>分辨率越大的特征图（延迟降采样）可以带来更高的分类精度，而这一观点从直觉上也可以很好理解，因为分辨率越大的输入能够提供的信息就越多。</p>
<p>上述三个策略中，前两个策略都是针对如何降低参数数量而设计的，最后一个旨在最大化网络精度。</p>
<p><strong>squeeze层</strong>借鉴了inception的思想，利用1x1卷积核来降低输入到expand层中3x3卷积核的输入通道数。</p>
<p>定义squeeze层中1x1卷积核的数量是<span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>s</mi><mrow><mn>1</mn><mo>∗</mo><mn>1</mn></mrow></msub></mrow><annotation encoding="application/x-tex">s_{1*1}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.58056em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathdefault">s</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span><span class="mbin mtight">∗</span><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>，类似的，expand层中1x1卷积核的数量是<span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>e</mi><mrow><mn>1</mn><mo>∗</mo><mn>1</mn></mrow></msub></mrow><annotation encoding="application/x-tex">e_{1*1}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.58056em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathdefault">e</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span><span class="mbin mtight">∗</span><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>， 3x3卷积核的数量是<span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>e</mi><mn>3</mn></msub><mo>∗</mo><mn>3</mn></mrow><annotation encoding="application/x-tex">e_3*3</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.61528em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathdefault">e</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">3</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∗</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">3</span></span></span></span>。令<span class="katex"><span class="katex-mathml"><math><semantics><mrow><msub><mi>s</mi><mrow><mn>1</mn><mo>∗</mo><mn>1</mn></mrow></msub><mo>&lt;</mo><msub><mi>e</mi><mrow><mn>1</mn><mo>∗</mo><mn>1</mn></mrow></msub><mo>+</mo><msub><mi>e</mi><mrow><mn>3</mn><mo>∗</mo><mn>3</mn></mrow></msub></mrow><annotation encoding="application/x-tex">s_{1*1} &lt; e_{1*1}+ e_{3*3}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6891em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathdefault">s</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span><span class="mbin mtight">∗</span><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&lt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.73333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathdefault">e</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span><span class="mbin mtight">∗</span><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.58056em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathdefault">e</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">3</span><span class="mbin mtight">∗</span><span class="mord mtight">3</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>从而保证输入到3x3的输入通道数减小。SqueezeNet的网络结构由若干个 fire module 组成</p>
<p><strong>速度考量</strong><br>
SqueezeNet在网络结构中大量采用1x1和3x3卷积核是有利于速度的提升的，对于类似caffe这样的深度学习框架，在卷积层的前向计算中，采用1x1卷积核可避免额外的im2col操作，而直接利用gemm进行矩阵加速运算，因此对速度的优化是有一定的作用的。</p>
<p>(4) mobilenet</p>
<p>mobilenet也是用卷积拆分的方法</p>
<figure data-type="image" tabindex="3"><img src="https://www.github.com/DragonFive/CVBasicOp/raw/master/1502694868072.jpg" alt="mobilenet" loading="lazy"></figure>
<p>作出更多共享的是有一个width Multiplier宽度参数和resolution Multiplier 分辨率参数 ，可以降低更多的参数。</p>
<p>没使用这两个参数的mobilenet是VGGNet的1/30.<br>
<img src="https://www.github.com/DragonFive/CVBasicOp/raw/master/1502695760857.jpg" alt="mobilenet" loading="lazy"></p>
<h1 id="权重参数量化与剪枝">权重参数量化与剪枝</h1>
<p>主要是通过权重剪枝，量化编码等方法来实现模型压缩。deep compression是float到uint的压缩,Binarized Neural Networks是 uint 到bool的压缩。</p>
<p>一些技巧：</p>
<ol>
<li>网络修剪<br>
采用当网络权重非常小的时候(小于某个设定的阈值),把它置0,就像二值网络一般；然后屏蔽被设置为0的权重更新，继续进行训练；以此循环，每隔训练几轮过后，继续进行修剪。</li>
<li>权重共享<br>
对于每一层的参数,我们进行k-means聚类,进行量化,对于归属于同一个聚类中心的权重,采用共享一个权重,进行重新训练.需要注意的是这个权重共享并不是层之间的权重共享,这是对于每一层的单独共享</li>
<li>增加L2权重<br>
增加L2权重可以让更多的权重，靠近0，这样每次修剪的比例大大增加。</li>
</ol>
<h2 id="deepcompresion">DeepCompresion</h2>
<figure data-type="image" tabindex="4"><img src="https://www.github.com/DragonFive/CVBasicOp/raw/master/1507039484844.jpg" alt="deep compression pipeline" loading="lazy"></figure>
<p>文章早期的工作，是Network Pruning，就是去除网络中权重低于一定阈值的参数后，重新<strong>finetune一个稀疏网络</strong>。在这篇文章中，则进一步添加了量化和编码，思路很清晰简单如下。</p>
<h3 id="网络剪枝移除不重要的连接">网络剪枝：移除不重要的连接</h3>
<p>（1） 普通网络训练；</p>
<p>（2） 删除权重小于一定阈值的连接得到<strong>稀疏网络</strong>；</p>
<p>（3） 对稀疏网络再训练；</p>
<h3 id="权重量化与共享">权重量化与共享</h3>
<p>此处的权值量化基于<strong>权值聚类</strong>，将连续分布的权值<strong>离散化</strong>，从而减小需要存储的权值数量。</p>
<p>让许多连接共享同一权重，使原始存储整个网络权重变为只需要存储码本(有效的权重)和索引；</p>
<p>对于一个4×4的权值矩阵，量化权重为4阶（-1.0，0，1.5，2.0）。</p>
<figure data-type="image" tabindex="5"><img src="https://www.github.com/DragonFive/CVBasicOp/raw/master/1502698285109.jpg" alt="量化过程" loading="lazy"></figure>
<p>对weights采用<strong>cluster index进行存储</strong>后，原来需要16个32bit float，现在只需要4个32bit float码字，与16个2bit uint索引，参数量为原来的(16×2+4×32)/(16×32)=0.31。</p>
<p>存储是没问题了，那如何对量化值进行更新呢？事实上，文中仅对码字进行更新。如上图：<strong>将索引相同的地方梯度求和乘以学习率</strong>，叠加到码字。</p>
<p>这样的效果，就等价于不断求取weights的聚类中心。原来有成千上万个weights，现在经过一个有效的聚类后，每一个weights都用其<strong>聚类中心进行替代</strong>.</p>
<p>看下表就知道最终的压缩效率非常可观，把500M的VGG压缩到到了11M，1/50。</p>
<figure data-type="image" tabindex="6"><img src="https://www.github.com/DragonFive/CVBasicOp/raw/master/1502698400878.jpg" alt="压缩VGG" loading="lazy"></figure>
<h3 id="霍夫曼编码更高效利用了权重的有偏分布">霍夫曼编码：更高效利用了权重的有偏分布；</h3>
<h2 id="binarized-neural-networks">Binarized Neural Networks</h2>
<ul>
<li>提出了一个BWN（Binary-Weight-Network）和XNOR-Network，前者只对网络参数做二值化，带来约32x的存储压缩和2x的速度提升，而后者对网络输入和参数都做了二值化，在实现32x存储压缩的同时带了58x的速度提升；</li>
<li>提出了一个新型二值化权值的算法；</li>
<li>第一个在大规模数据集如ImageNet上提交二值化网络结果的工作；</li>
<li>无需预训练，可实现training from scratch。</li>
</ul>
<h1 id="reference">reference</h1>
<p><a href="https://cloud.tencent.com/community/article/678192">CNN 模型压缩与加速算法综述</a></p>
<p><a href="https://zhuanlan.zhihu.com/p/25797790">知乎:为了压榨CNN模型，这几年大家都干了什么</a></p>
<p><a href="http://blog.csdn.net/hjimce/article/details/51564774"> 深度学习（六十）网络压缩简单总结</a></p>
<p><a href="https://dragonfive.github.io/2017-07-17/mobilenets/">mobile_net的模型优化</a></p>
<p><a href="https://dragonfive.github.io/2017-07-20/squeeze_net/">squeeze_net的模型优化</a></p>
<p><a href="https://dragonfive.github.io/2017-07-05/deep_learning_model/">神经网络模型演化</a></p>

          </div>
        </div>

        
          <div class="next-post">
            <a class="purple-link" href="https://dragonfive.gitee.io/post/cpp11-newfeature/">
              <h3 class="post-title">
                下一篇：c++使用7年后的经验总结
              </h3>
            </a>
          </div>
          
      </div>

      

      <div class="site-footer">
  <div class="slogan">邮箱(base64)：MTY5MDMwMjk2M0BxcS5jb20=
</div>
  <div class="social-container">
    
      
        <a href="https://github.com/DragonFive" target="_blank">
          <i class="fab fa-github"></i>
        </a>
      
    
      
    
      
    
      
    
      
    
  </div>
  Powered by <a href="https://github.com/getgridea/gridea" target="_blank">Gridea</a> | <a class="rss" href="https://dragonfive.gitee.io//atom.xml" target="_blank">RSS</a>
</div>


    </div>
    <script type="application/javascript">

hljs.initHighlightingOnLoad()

var app = new Vue({
  el: '#app',
  data: {
    menuVisible: false,
  },
})

</script>




  </body>
</html>
